package net.peelmeagrape.hibernate;

import net.peelmeagrape.hibernate.xmlgen.XmlAttribute;
import net.peelmeagrape.hibernate.xmlgen.XmlElement;
import net.peelmeagrape.hibernate.xmlgen.AddPropertyNameAsAttribute;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;

/**
 * The {@link Version} element is optional and indicates that the table contains versioned data.
 * This is particularly useful if you plan to use
 * <a href="{@docRoot}/reference/en/html/transactions.html#transactions-optimistic">Optimistic concurrency control;</a>.
 * <br/>
 * <br/>
 * A version or timestamp property should never be null for a detached instance,
 * so Hibernate will detact any instance with a null version or timestamp as
 * transient, no matter what other unsaved-value strategies are specified.
 * Declaring a nullable version or timestamp property is an easy way to avoid
 * any problems with transitive reattachment in Hibernate, especially useful
 * for people using assigned identifiers or composite keys!
 */
@Target({METHOD,FIELD}) @Retention(RUNTIME)
@XmlElement(name="version")
@AddPropertyNameAsAttribute(name="name")
public @interface Version
{
    Meta[] meta() default {};
    @XmlAttribute String node() default "";

    /**
     * The strategy Hibernate should use for accessing the property value. This may be one of
     * 'property', 'field', 'embedded', or the name of a subclass of {@link org.hibernate.property.PropertyAccessor}.
     */
    @XmlAttribute String access() default "property";

    /**
     *  (optional - defaults to the property name): The name of the column holding the version number.
     */
    @XmlAttribute String column() default "";

    /**
     * (optional - defaults to integer): The type of the version number.
     *  Version numbers may be of Hibernate type long, integer, short, timestamp or calendar.
     */
    @XmlAttribute String type() default "integer";

    /**
     * (optional - defaults to undefined): A version property value that indicates that an instance is newly
     * instantiated (unsaved), distinguishing it from detached instances that were saved or loaded in a
     * previous session. ({@link UnsavedValue#UNDEFINED} specifies that the identifier property value should be used.)
     */
    @XmlAttribute("unsaved-value") UnsavedValue unsavedValue() default UnsavedValue.UNDEFINED;

    /**
     * What value of the field represents an unsaved entity.
     */
    public static enum UnsavedValue
    {
        NULL("null"),
        NEGATIVE("negative"),
        UNDEFINED("undefined");
        private String value;

        UnsavedValue(String value)
        {
            this.value = value;
        }

        public String toString()
        {
            return value;
        }
    }

}
